﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using Red.Core.Extensions;

namespace Red.Core
{
    public class ResourceTypeInfo
    {
        #region Data

        private const string s_defImage = "default.png";
        private static string[] s_hiddenFilesExtensions = new string[0];
        private static Dictionary<string, ResourceTypeInfo> s_infos = new Dictionary<string, ResourceTypeInfo>();

        private ImageSource _img;
        private Uri _imgUri;

        #endregion

        #region Properties

        public string Extension { get; private set; }

        public string Name { get; private set; }

        public string Editor { get; private set; }

        public bool UsesEngine { get; private set; }

        public ImageSource Icon 
        {
            get
            {   // image is loaded lazily for 3 reasons:
                // 1. to spread the workload 
                // 2. to save some time if the image is not displayed at all
                // 3. to allow pre-caching to be done on separate thread (BitmapImage has to be created in UI thread if it wants to be used as a binding source)
                if ( _img == null && _imgUri != null )
                {
                    try
                    {
                        _img = new BitmapImage( _imgUri );
                    }
                    catch ( System.IO.IOException )
                    {
                        _imgUri = null; // do not try again
                    }
                }

                return _img;
            }
        }

        #endregion Properties

        #region Public methods

        /// <summary>
        ///     
        /// </summary>
        /// <param name="ext"></param>
        /// <returns>
        /// ResourceTypeInfo for given extension or null if the file is hidden. Non-registered resources are given a default info.
        /// </returns>
        public static ResourceTypeInfo GetForExtension( string ext )
        {
            if ( s_infos.Count == 0 )
            {
                PreCache();
            }

            if ( ext.StartsWith( "." ) ) 
                ext = ext.Substring( 1 );

            ResourceTypeInfo info;
            s_infos.TryGetValue( ext, out info );

            if ( info == null )
            {
                if ( s_hiddenFilesExtensions.Contains( ext ) )
                {
                    return null;
                }

                // create info for unknown file
                info = new ResourceTypeInfo
                {
                    Extension = ext,
                    Name      = ext + " file",
                    _imgUri   = new ResourceUri( "FileIcons/" + s_defImage )
                };
            }

            return info;
        }

        #endregion Public methods

        #region Private methods

        private static void PreCache()
        {
            try
            {
                XDocument doc = XDocument.Load( "Data/ResourceBindings.xml" );
                var hiddenFilesStr = doc.Root.Attribute( "HiddenExtensions" ).Value;
                s_hiddenFilesExtensions = hiddenFilesStr.Split( new[] { ';', ',' } );

                var data = from tag in doc.Descendants( "ResourceBinding" )
                           select new ResourceTypeInfo
                           {
                               Extension  = tag.Attribute( "Extension" ).Value,
                               Name       = tag.Attribute( "Name" ).Value,
                               _imgUri    = new ResourceUri( "FileIcons/" + tag.Attribute( "Icon" ).Value ?? s_defImage ),
                               Editor     = tag.Attribute( "Editor" ).Value,
                               UsesEngine = bool.Parse( tag.Attribute( "UsesEngine" )?.Value ?? bool.TrueString ) // this is optional and defaults to true
                           };

                s_infos = data.ToDictionary( info => info.Extension );
            }
            catch ( System.IO.IOException )
            {
            }
        }

        #endregion
    }
}
